package cn.sirun.com.fca.personal.center.model.service;

import android.text.TextUtils;

import com.tencent.cloud.iov.kernel.IovKernel;
import com.tencent.cloud.iov.kernel.model.BaseResponse;
import com.tencent.cloud.iov.util.rx.OnErrorCacheOnSubscribe;
import com.tencent.cloud.iov.util.rx.RxUtils;
import com.tencent.cloud.iov.util.rx.SimpleObserver;
import com.tencent.cloud.iov.util.rx.SingleElementObserver;
import com.tencent.cloud.iov.util.storage.TXCacheManager;
import com.tencent.cloud.iov.util.storage.TXSharedPreferencesUtils;

import java.util.concurrent.Callable;

import cn.sirun.com.fca.account.constant.AccountCommonConst;
import cn.sirun.com.fca.account.model.login.PersonalInfo;
import cn.sirun.com.fca.account.model.login.PersonalInfoRequest;
import cn.sirun.com.fca.account.model.profile.Reseller;
import cn.sirun.com.fca.account.uitl.PersonalInfoUtils;
import cn.sirun.com.fca.personal.center.repo.ProfileRepository;
import io.reactivex.Notification;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;

/**
 * 个人资料管理类
 *
 * @author showxiao
 * @date 2018/10/17
 */
public final class PersonalInfoManager {

    private static volatile PersonalInfoManager sInstance;

    public static PersonalInfoManager getInstance() {
        if (sInstance == null) {
            synchronized (PersonalInfoManager.class) {
                if (sInstance == null) {
                    sInstance = new PersonalInfoManager();
                    subscribeDestroyNotification();
                }
            }
        }

        return sInstance;
    }

    private static void subscribeDestroyNotification() {
        PersonalCenterServices.getDestroyObservable()
                .subscribe(new SingleElementObserver<Boolean>() {
                    @Override
                    public void onNext(Boolean b) {
                        super.onNext(b);
                        destroy();
                    }
                });
    }

    public static void destroy() {
        if (sInstance != null) {
            synchronized (PersonalInfoManager.class) {
                if (sInstance != null) {
                    sInstance.onDestroy();
                    sInstance = null;
                }
            }
        }
    }

    /**
     * 清空个人资料
     */
    public static void clearLocalPersonalInfo() {
        PersonalInfoUtils.savePersonalInfo(null);
    }

    /**
     * 个人资料数据源
     * <p>
     * 即发射有效数据，也发射网络错误
     */
    private BehaviorSubject<Notification<PersonalInfo>> mPersonalInfoSubject;

    /**
     * 个人资料内存缓存
     * <p>
     * 仅发射最新有效数据（本地及网络数据）
     */
    private BehaviorSubject<PersonalInfo> mCacheSubject;

    /**
     * 请求个人资料订阅管理
     */
    private Disposable mPersonalInfoDisposable;

    /**
     * 请求状态标识，避免重复请求
     */
    private boolean mIsRequestingPersonalInfo;

    /**
     * 请求网络数据标识，用于判断是否成功获取网络有效数据
     */
    private boolean mHasFetchedRemoteData;

    private PersonalInfoManager() {
        mPersonalInfoSubject = BehaviorSubject.create();
        mCacheSubject = BehaviorSubject.create();
        mIsRequestingPersonalInfo = false;

        // 初始化本地数据
        PersonalInfo localPersonalInfo = PersonalInfoUtils.getPersonalInfo();
        if (localPersonalInfo == null) {
            localPersonalInfo = new PersonalInfo();

            String phoneInfo = TXSharedPreferencesUtils.getValue(
                    AccountCommonConst.KEY_USER_PHONE_INFO
            );

            if (!TextUtils.isEmpty(phoneInfo)) {
                String[] phoneInfoArr = phoneInfo.split(AccountCommonConst.NATION_PHONE_SPLITTER);
                if (phoneInfoArr.length == 2) {
                    localPersonalInfo.setUserNation(phoneInfoArr[0]);
                    localPersonalInfo.setUserPhone(phoneInfoArr[1]);
                }
            }

        }
        mCacheSubject.onNext(localPersonalInfo);

        // 注册手机号变更通知
        TXCacheManager.getInstance().registerCacheChangeListener(
                AccountCommonConst.KEY_USER_PHONE_INFO, new TXCacheManager.OnCacheChangeListener() {
                    @Override
                    public void onCacheChanged(String key, String value) {
                        String[] phoneInfo = value.split(AccountCommonConst.NATION_PHONE_SPLITTER);
                        if (phoneInfo.length == 2) {
                            updatePhoneInfo(phoneInfo[0], phoneInfo[1]);
                        }
                    }
                }
        );
    }

    /**
     * 获取个人资料数据源
     * <p>
     * 即发射本地数据，也发射网络数据，此外也会发射网络请求错误
     *
     * @return
     */
    public Observable<PersonalInfo> getPersonalInfoObservable() {
        return mPersonalInfoSubject
                .observeOn(Schedulers.io())
                .compose(new OnErrorCacheOnSubscribe<>(mCacheSubject))
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        if (!mHasFetchedRemoteData) {
                            requestPersonalInfo();
                        }
                    }
                });
    }

    /**
     * 请求个人资料
     * <p>
     * 即查询本地数据，也请求网络数据
     */
    private synchronized void requestPersonalInfo() {
        if (mIsRequestingPersonalInfo) {
            return;
        }

        PersonalInfoRequest request = new PersonalInfoRequest(
                IovKernel.getQQAppId(), IovKernel.getWeChatAppId()
        );

        ProfileRepository.getInstance().getPersonalInfo(request)
                .subscribeOn(Schedulers.io())
                .map(new Function<BaseResponse<PersonalInfo>, PersonalInfo>() {
                    @Override
                    public PersonalInfo apply(BaseResponse<PersonalInfo> response)
                            throws Exception {
                        return response.getData();
                    }
                })
                .compose(new RequestStateTransformer())
                .compose(new LocalPersonalInfoTransformer())
                .subscribe(new PersonalInfoObserver());
    }

    /**
     * 获取个人资料
     *
     * @return
     */
    public PersonalInfo getPersonalInfo() {
        return mCacheSubject.getValue();
    }

    /**
     * 如果未成功请求网络数据，将执行网络请求
     */
    public void refreshPersonalInfoIfNeeded() {
        if (!mHasFetchedRemoteData) {
            requestPersonalInfo();
        }
    }

    /**
     * 更新人个头像
     *
     * @param iconUrl
     * @param imageFileNameCacheKey
     */
    public void updateHeadPortrait(String iconUrl, String imageFileNameCacheKey) {
        PersonalInfo personalInfo = getPersonalInfo();
        if (null != personalInfo) {
            personalInfo.setIconUrl(iconUrl);
            // TODO: 2018/10/17 @vinson @showxiao ???
            TXSharedPreferencesUtils.remove(personalInfo.getHeadPortraitFileNameCacheKey());
            personalInfo.setHeadPortraitFileNameCacheKey(imageFileNameCacheKey);

            updatePersonalInfo(personalInfo);
        }
    }

    /**
     * 更新邮箱
     *
     * @param emial
     */
    public void updateEmail(String emial) {
        PersonalInfo personalInfo = getPersonalInfo();
        if (personalInfo != null) {
            personalInfo.setEmail(emial);

            updatePersonalInfo(personalInfo);
        }
    }

    /**
     * 更新用户昵称
     *
     * @param nick
     */
    public void updateNickName(String nick) {
        PersonalInfo personalInfo = getPersonalInfo();
        if (personalInfo != null) {
            personalInfo.setNick(nick);

            updatePersonalInfo(personalInfo);
        }
    }

    /**
     * 更新紧急联系人
     *
     * @param name
     * @param phone
     */
    public void updateEmergencyInfo(String name, String phone) {
        PersonalInfo personalInfo = getPersonalInfo();
        if (null != personalInfo) {
            personalInfo.setEmergencyContactPerson(name);
            personalInfo.setEmergencyContactNumber(phone);

            updatePersonalInfo(personalInfo);
        }
    }


    /**
     * 更新手机号
     *
     * @param phone
     */
    public void updatePhoneInfo(String nation, String phone) {
        PersonalInfo personalInfo = getPersonalInfo();
        if (personalInfo != null) {
            personalInfo.setUserNation(nation);
            personalInfo.setUserPhone(phone);

            updatePersonalInfo(personalInfo);
        }
    }

    /**
     * 更新经销商
     *
     * @param reseller
     */
    public void updateReseller(Reseller reseller) {
        PersonalInfo personalInfo = getPersonalInfo();
        if (personalInfo != null) {
            personalInfo.setReseller(reseller);
            updatePersonalInfo(personalInfo);
        }
    }

    /**
     * 更新个人资料
     * <p>
     * 如果当前有订阅者，将会收到数据源发射的新数据通知
     *
     * @param personalInfo
     */
    private void updatePersonalInfo(PersonalInfo personalInfo) {
        // 更新至本地
        PersonalInfoUtils.savePersonalInfo(personalInfo);
        // 更新至内存缓存
        mCacheSubject.onNext(personalInfo);
        // 更新至数据源（通知至订阅者）
        mPersonalInfoSubject.onNext(Notification.createOnNext(personalInfo));
    }

    private void onDestroy() {
        TXCacheManager.getInstance().unRegisterCacheChangeListener(
                AccountCommonConst.KEY_USER_PHONE_INFO
        );

        RxUtils.dispose(mPersonalInfoDisposable);
        mPersonalInfoDisposable = null;
    }

    /**
     * 请求状态管理
     */
    private class RequestStateTransformer implements ObservableTransformer<PersonalInfo, PersonalInfo> {
        @Override
        public ObservableSource<PersonalInfo> apply(Observable<PersonalInfo> upstream) {
            return upstream
                    .doOnSubscribe(new Consumer<Disposable>() {
                        @Override
                        public void accept(Disposable disposable) throws Exception {
                            mIsRequestingPersonalInfo = true;
                        }
                    })
                    .doOnNext(new Consumer<PersonalInfo>() {
                        @Override
                        public void accept(PersonalInfo personalInfo) throws Exception {
                            if (personalInfo != null) {
                                mHasFetchedRemoteData = true;
                            }
                            mIsRequestingPersonalInfo = false;
                        }
                    })
                    .doOnError(new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            mIsRequestingPersonalInfo = false;
                        }
                    });
        }
    }


    /**
     * 本地数据存取管理
     */
    private class LocalPersonalInfoTransformer implements ObservableTransformer<PersonalInfo, PersonalInfo> {

        @Override
        public ObservableSource<PersonalInfo> apply(Observable<PersonalInfo> upstream) {
            return upstream
                    .doOnNext(new Consumer<PersonalInfo>() {
                        @Override
                        public void accept(PersonalInfo personalInfo) throws Exception {
                            // 存储至本地
                            if (personalInfo != null) {
                                PersonalInfoUtils.savePersonalInfo(personalInfo);
                            }
                        }
                    })
                    .startWith(Observable.defer(new Callable<ObservableSource<? extends PersonalInfo>>() {
                        @Override
                        public ObservableSource<? extends PersonalInfo> call() throws Exception {
                            // 未获取过有效数据，先发射本地缓存
                            if (!mPersonalInfoSubject.hasValue()
                                    || mPersonalInfoSubject.getValue() == null) {

                                PersonalInfo personalInfo = getPersonalInfo();
                                if (personalInfo != null) {
                                    return Observable.just(personalInfo);
                                }
                            }

                            return Observable.empty();
                        }
                    }))
                    .onErrorResumeNext(new Function<Throwable, ObservableSource<? extends PersonalInfo>>() {
                        @Override
                        public ObservableSource<? extends PersonalInfo> apply(Throwable throwable) throws Exception {
                            // 请求返回失败：如果发射过本地数据，则不通知此次失败结果
                            if (getPersonalInfo() != null) {
                                return Observable.empty();
                            }

                            return Observable.error(throwable);
                        }
                    });
        }
    }

    /**
     * 个人资料数据观察者
     */
    private class PersonalInfoObserver extends SimpleObserver<PersonalInfo> {

        @Override
        public void onSubscribe(Disposable d) {
            super.onSubscribe(d);
            RxUtils.dispose(mPersonalInfoDisposable);
            mPersonalInfoDisposable = d;
        }

        @Override
        public void onNext(PersonalInfo personalInfo) {
            super.onNext(personalInfo);
            mCacheSubject.onNext(personalInfo);
            mPersonalInfoSubject.onNext(Notification.createOnNext(personalInfo));
        }

        @Override
        public void onError(Throwable e) {
            super.onError(e);
            mPersonalInfoSubject.onNext(Notification.<PersonalInfo>createOnError(e));
        }
    }
}
